using System;
using System.Text.RegularExpressions;
using TDUnit.Common.TestData;

namespace TDUnit.Common.Resolver
{
    public class DependencyResolver
    {
        private const string resolvePattern = @"^\$\((?<table>\w+)\.(?<row>\w+)\.(?<column>\w+)\)$";
        private readonly TestData.TestData dataset;

        public DependencyResolver(TestData.TestData dataset)
        {
            if(dataset == null)
                throw new ArgumentNullException("dataset");

            this.dataset = dataset;
        }

        public bool ShouldResolve(string value)
        {
            return Regex.IsMatch(value, resolvePattern);
        }

        public Column Resolve(string resolvableValue)
        {
            if(dataset.Tables.Length == 0)
                throw new DependencyResolverException("The dataset must contain at least one table.");

            if (!ShouldResolve(resolvableValue))
                throw new InvalidOperationException("The value '{0}' cannot be resolved. Resolvable values should be structured as '$(TableName.RowName.ColumnName)'.");

            var tableName = ExtractTableName(resolvableValue);
            var table = dataset.GetTable(tableName);
            if (table == null)
                throw new DependencyResolverException(string.Format("A table with name '{0}' does not exist in the dataset or has not been defined before its use.", tableName));

            var rowName = ExtractRowName(resolvableValue);
            var row = table.GetRow(rowName);
            if(row == null)
                throw new DependencyResolverException(string.Format("A row with name '{0}' does not exist in table '{1}' or has not been defined before its use.", rowName, tableName));

            var columnName = ExtractColumnName(resolvableValue);
            var column = columnName.Equals(row.PrimaryKeyColumn.Name) ? row.PrimaryKeyColumn : row.GetColumn(columnName);
            if (column == null)
                throw new DependencyResolverException(string.Format("A column with name '{0}' does not exist in row '{1}' for table '{2}' or has not been defined before its use.", columnName, rowName, tableName));

            return column;
        }

        #region Extract values
        public static string ExtractTableName(string resolveValue)
        {
            return GetRegexGroupValue(resolveValue, "table");
        }

        public static string ExtractRowName(string resolveValue)
        {
            return GetRegexGroupValue(resolveValue, "row");
        }

        public static string ExtractColumnName(string resolveValue)
        {
            return GetRegexGroupValue(resolveValue, "column");
        }
        #endregion

        #region Helper methods
        private static string GetRegexGroupValue(string resolveValue, string groupName)
        {
            var match = Regex.Match(resolveValue, resolvePattern);
            var tableGroup = match.Groups[groupName];
            return tableGroup == null ? string.Empty : tableGroup.Value;
        }
        #endregion
    }
}